package com.baixiaowen.javaefficientprogramming.stream.cases;

import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 【排序】- 在股票中，撮合交易的原则是一段时间内的交易申请，价格越高的先成交；
 * 价格一样，下单时间最早的先成交；价格和时间一致，交易量大的先成交；如果价格、时间和交易量都一致，
 * 机构优先成交，散会最后成交。现有一批交易申请数据，需要确认交易先后顺序
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class CaseFive {

    /**
     * 交易实体模型
     */
    @Data
    @AllArgsConstructor
    class Trade {
        // 下单价格
        private BigDecimal price;
        // 下单时间
        private LocalDateTime time;
        // 下单量
        private Integer count;
        // 下单类型：机构 / 个人
        private String type;
    }

    /**
     * 一段时间内的交易申请
     */
    List<Trade> trades;

    @BeforeAll
    public void init() {
        trades = new ArrayList<>();

        trades.add(new Trade(new BigDecimal(100),
                // 在当前时间的基础上添加 1 秒
                LocalDateTime.now().plusSeconds(1),
                500, "机构"));
        trades.add(new Trade(new BigDecimal(101),
                LocalDateTime.now().plusSeconds(2),
                1, "个人"));
        trades.add(new Trade(new BigDecimal(101),
                LocalDateTime.now().plusSeconds(1),
                1, "个人"));
        trades.add(new Trade(new BigDecimal(100),
                LocalDateTime.now().plusSeconds(1),
                500, "个人"));
        trades.add(new Trade(new BigDecimal(100),
                LocalDateTime.now().plusSeconds(0),
                2, "个人"));
        trades.add(new Trade(new BigDecimal(100),
                LocalDateTime.now().plusSeconds(0),
                100, "机构"));
    }

    @Test
    public void sortTrade() {
        System.out.println(JSON.toJSONString(trades, true));

        List<Trade> sorted = trades.stream()
                // 首先按照价格排序
                .sorted(Comparator.comparing(
                                Trade::getPrice,
                                // TODO 进行排序调整，将自然排序翻转
                                Comparator.reverseOrder())
                        // 时间先后进行排序， 自然排序
                        .thenComparing(Trade::getTime)
                        // 交易量进行排序，自然排序倒序
                        .thenComparing(Trade::getCount, Comparator.reverseOrder())
                        // 自定义排序规则
                        .thenComparing(Trade::getType, (type1, type2) -> {
                            // -1:type1在先 1:type2在先
                            if ("机构".equals(type1) && "个人".equals(type2)) {
                                return -1;
                            } else if ("个人".equals(type1) && "机构".equals(type2)) {
                                return 1;
                            } else {
                                return 0;
                            }
                        }))
                .collect(Collectors.toList());
        System.err.println(JSON.toJSONString(sorted, true));

    }

}
